package org.hismig.partition;

import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;

import javax.sql.DataSource;

import org.hismig.cfg.DBConnection;
import org.hismig.cfg.DynamicPartition;
import org.hismig.cfg.partition.Configuration;
import org.hismig.cfg.partition.ConfigurationHelper;
import org.hismig.migration.Context;
import org.hismig.utils.CheckTool;
import org.hismig.utils.EncryptTool;
import org.hismig.utils.JDBCTool;
import org.hismig.utils.StringTool;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * @declare: //TODO <br />
 *           This class created by Vansion.Hopihit on 2012-07-04 <br />
 *           <a href="mailto:vansionhopihit@gmail.com">Contact Me</a>
 * @version 1.0
 * @author Vansion.Hopihit
 * 
 */
public abstract class PartitionBase implements IDynamicPartition {

	private static Logger logger = LoggerFactory.getLogger(PartitionBase.class);

	protected DynamicPartition dynamicPartition; // cfg

	protected String driver;
	protected String baseUrl;
	protected String user;
	protected String password;
	protected String createDBUrl;

	protected String dbName;

	protected DataSource currentDS;
	protected String currentSelection;

	@Override
	public DataSource getDataSource(Context context) throws SQLException {

		List<DBConnection> dbConnections;

		// Check cfg file exists
		logger.debug(String.format(
				"Start to check the database[:%s] cfg file if exists", dbName));
		if (Configuration.checkCfgFile(dbName)) {

			logger.info(String.format("The database[:%s] cfg file is exists",
					dbName));

			dbConnections = Configuration.getShardDBConnections(dbName);

			DBConnection dbConnection = ConfigurationHelper.getDBConnection(
					dbName, dbConnections, context);

			if (null != dbConnection) {
				String condition = dbConnection
						.getParamByName(IDynamicPartition.KEY_SELECTION);

				if (!condition.equals(currentSelection)) {
					cacheCurrentDataSource(condition,
							JDBCTool.getDataSource(dbConnection));
				}
				return currentDS;
			}
		} else {
			logger.info(String.format(
					"The database[:%s] cfg file do not exists", dbName));
			dbConnections = new ArrayList<DBConnection>();
		}

		// create dbContition
		logger.debug("Start to make a new Database");
		DBConnection newDBConnection = makeNewDBConnection(dbConnections.size() + 1);
		logger.info("Make a new Database completely");

		CheckTool.checkNotNull(newDBConnection);
		cacheCurrentDataSource(
				newDBConnection.getParamByName(IDynamicPartition.KEY_SELECTION),
				JDBCTool.getDataSource(newDBConnection));

		// update cfg file
		dbConnections.add(newDBConnection);
		logger.debug(String.format("Start to update Database[:%s] cfg file",
				dbName));
		Configuration.saveOrUpdateXmlFile(dbName, dbConnections);
		logger.info(String.format("Update Database[:%s] cfg file completely",
				dbName));
		return currentDS;
	}

	protected void cacheCurrentDataSource(String condition,
			DataSource dataSource) {
		CheckTool.checkNotEmpty(condition);
		CheckTool.checkNotNull(dataSource);

		if (!condition.equals(currentSelection)) {
			currentSelection = condition;

			JDBCTool.closeQuietly(currentDS);
			currentDS = dataSource;
		}
	}

	protected abstract DBConnection makeNewDBConnection(int index)
			throws SQLException;

	protected abstract void setDynamicPartitonEx(
			DynamicPartition dynamicPartition);

	protected String getRealDBName(int index) {
		return String.format("%s_%s", new Object[]{dbName, index});
	}

	protected String getRealDBUrl(int index) {
		return StringTool.replaceString(baseUrl,
				IDynamicPartition.SYMBOL_DBNAME, getRealDBName(index));
	}

	@Override
	public void setDynamicPartition(DynamicPartition dynamicPartition) {
		CheckTool.checkNotNull(dynamicPartition);
		this.dynamicPartition = dynamicPartition;

		driver = dynamicPartition.getParamByName(IDynamicPartition.KEY_DRIVER);
		baseUrl = dynamicPartition
				.getParamByName(IDynamicPartition.KEY_BASEURL);
		user = dynamicPartition.getParamByName(IDynamicPartition.KEY_USER);
		password = dynamicPartition
				.getParamByName(IDynamicPartition.KEY_PASSWORD);
		createDBUrl = dynamicPartition
				.getParamByName(IDynamicPartition.KEY_CREATEDBURL);

		CheckTool.checkNotEmpty(driver);
		CheckTool.checkNotEmpty(baseUrl);
		CheckTool.checkNotEmpty(user);
		CheckTool.checkNotEmpty(password);

		if (dynamicPartition.isEncrypt()) {
			user = EncryptTool.decrypt(user);
			password = EncryptTool.decrypt(password);
		}

		dbName = dynamicPartition.getParent().getParent().getName();

		setDynamicPartitonEx(dynamicPartition);
	}

}
